//
//  DeInit.swift
//  cnswift-demo
//
//  Created by YangWei on 2021/1/2.
//  Copyright © 2021 YangWei. All rights reserved.
//

import UIKit

class Deinitialization: SWDBaseObject {
    
    class func run() {
        let deinitialization = Deinitialization()
        
        // 2
        deinitialization.deinitializersInAction()
    }
    
    /// 2 析构器实践
    func deinitializersInAction() {
        let title = "2 析构器实践";
        printStartLine(title)
        
        /*
         创建一个 Player 实例，向 Bank 对象申请得到 100 个硬币
         使用一个可选类型的变量：玩家可以随时离开游戏，设置为可选，可以追踪玩家当前是否在游戏中
         */
        var playerOne: PlayerV2? = PlayerV2(coins: 100)
        print("A new player has joined the game with \(playerOne!.coinsInPurse) coins")
        // 打印“A new player has joined the game with 100 coins”
        print("There are now \(Bank.coinsInBank) coins left in the bank")
        // 打印“There are now 9900 coins left in the bank”

        /*
         playerOne 是可选，在访问其 coinsInPurse 属性来打印钱包中的硬币数量和调用 win(coins:) 方法时，使用感叹号（!）强制解包：
         */
        playerOne!.win(coins: 2_000)
        print("PlayerOne won 2000 coins & now has \(playerOne!.coinsInPurse) coins")
        // 打印“PlayerOne won 2000 coins & now has 2100 coins”

        // 玩家已经赢得 2,000 枚硬币，玩家钱包中现在有 2,100 枚硬币，而 Bank 对象只剩余 7,900 枚硬币
        print("The bank now only has \(Bank.coinsInBank) coins left")
        // 打印“The bank now only has 7900 coins left”

        /*
         玩家离开游戏，设置 playerOne 变量为 nil
         playerOne 变量对 Player 实例的引用没有了
         也没有其他的属性或者变量仍在引用这个 Player 实例，它将会被释放掉以节约内存
         */
        playerOne = nil
        // 打印 "a player is deiniting" 记录deinit被调用
        print("PlayerOne has left the game")
        // 打印“PlayerOne has left the game”
        print("The bank now has \(Bank.coinsInBank) coins")
        // 打印“The bank now has 10000 coins”
        
        printEndLine(title)
    }
}

/// 2 析构器实践
/// 一个简单的游戏，定义两种新类型，分别是 Bank 和 Player。
/// Bank：管理一种虚拟硬币，确保流通的硬币数量永远不可能超过 10,000
class Bank {
    // 使用类型属性和类型方法来存储和管理其当前状态
    // 使用 coinsInBank 属性跟踪它当前拥有的硬币数量
    static var coinsInBank = 10_000
    
    // 处理硬币的分发
    static func distribute(coins numberOfCoinsRequested: Int) -> Int {
        // 分发硬币之前检查是否有足够的硬币
        let numberOfCoinsToVend = min(numberOfCoinsRequested, coinsInBank)
        coinsInBank -= numberOfCoinsToVend
        return numberOfCoinsToVend
    }
    
    // 处理硬币的收集
    static func receive(coins: Int) {
        // 接收到的硬币数目加回硬币存储中
        coinsInBank += coins
    }
}

/// 游戏中的一个玩家：在任意时间都有一定数量的硬币存储在他们的钱包中
class PlayerV2 {
    // 表示玩家的钱包
    var coinsInPurse: Int
    
    init(coins: Int) {
        // 初始化的过程，从 Bank 对象获取指定数量的硬币
        // 如果没有足够的硬币可用，能会收到比指定数量少的硬币
        coinsInPurse = Bank.distribute(coins: coins)
    }
    
    // 从 Bank 对象获取一定数量的硬币，并把它们添加到玩家的钱包
    func win(coins: Int) {
        coinsInPurse += Bank.distribute(coins: coins)
    }
    
    // 析构器在 Player 实例释放前被调用
    deinit {
        // 将玩家的所有硬币都返还给 Bank 对象
        Bank.receive(coins: coinsInPurse)
        print("a player is deiniting")
    }
}
